package indicator.calculate;

import java.io.Serializable;
import java.util.List;

import entity.exchange.KlineResult;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NonNull;
import lombok.RequiredArgsConstructor;
/**
 * kdj 计算方式
 * https://baike.baidu.com/item/KDJ%E6%8C%87%E6%A0%87/6328421?fromtitle=kdj&fromid=3423560
 */
@Data
@RequiredArgsConstructor
public class Kdj implements Serializable {
	private static final long serialVersionUID = -3794791753676256084L;
	//可以配置参数,这个默认跟zb网站一致
	private final int m_iParam[] = { 9, 3, 3 };
	private double m_data[][];

	private @NonNull List<KlineResult> klines;

	public KdjEntity getKdj() {
		m_data = new double[3][klines.size()];
		int n1 = m_iParam[0];
		int n2 = m_iParam[1];
		int n3 = m_iParam[2];
		if (klines == null || n1 > klines.size() || n1 < 1)
			return null;
		double kvalue[] = m_data[0];
		double dvalue[] = m_data[1];
		double jvalue[] = m_data[2];
		n2 = n2 > 0 ? n2 : 3;
		n3 = n3 > 0 ? n3 : 3;
		double maxhigh = (double) klines.get(n1 - 1).getHigh();
		double minlow = (double) klines.get(n1 - 1).getLow();
		for (int j = n1 - 1; j >= 0; j--) {
			if (maxhigh < klines.get(j).getHigh())
				maxhigh = (double) klines.get(j).getHigh();
			if (minlow < klines.get(j).getLow())
				minlow = (double) klines.get(j).getLow();
		}

		double rsv;
		if (maxhigh <= minlow) {
			rsv = 50F;
		} else {
			//主要计算出rsv
			rsv = (double) (((klines.get(n1 - 1).getClose() - minlow) / (maxhigh - minlow)) * 100F);
		}
		double prersv;
		kvalue[n1 - 1] = dvalue[n1 - 1] = jvalue[n1 - 1] = prersv = rsv;
		for (int i = 0; i < n1; i++) {
			kvalue[i] = 0.0F;
			dvalue[i] = 0.0F;
			jvalue[i] = 0.0F;
		}

		for (int i = n1; i < klines.size(); i++) {
			maxhigh = (double) klines.get(i).getHigh();
			minlow = (double) klines.get(i).getLow();
			for (int j = i - 1; j > i - n1; j--) {
				if (maxhigh < klines.get(j).getHigh())
					maxhigh = (double) klines.get(j).getHigh();
				if (minlow > klines.get(j).getLow())
					minlow = (double) klines.get(j).getLow();
			}

			if (maxhigh <= minlow) {
				rsv = prersv;
			} else {
				prersv = rsv;
				rsv = (double) (((klines.get(i).getClose() - minlow) / (maxhigh - minlow)) * 100F);
			}

			// kdj.setRsv(rsv);
			kvalue[i] = (kvalue[i - 1] * (double) (n2 - 1)) / (double) n2 + rsv / (double) n2;
			dvalue[i] = kvalue[i] / (double) n3 + (dvalue[i - 1] * (double) (n3 - 1)) / (double) n3;
			jvalue[i] = 3F * kvalue[i] - 2.0F * dvalue[i];
		}
		KdjEntity kdj = new KdjEntity();
		kdj.setK(kvalue);
		kdj.setD(dvalue);
		kdj.setJ(jvalue);
		return kdj;
	}
	
	@Data
	public static class KdjEntity implements Serializable {
		private static final long serialVersionUID = -2451088649422502256L;
		private double[] k;
		private double[] d;
		private double[] j;
//		private double rsv;

		@Data
		@AllArgsConstructor
		public class KdjOne {
			private double k;
			private double d;
			private double j;

			public String toString() {
				return "超 k:" + k + " d:" + d + " j:" + j;
			}
		}

		public KdjOne getOne(int i) {
			return new KdjOne(k[i], d[i], j[i]);
		}

		public KdjOne getLast() {
			int last = k.length - 1;
			return new KdjOne(k[last], d[last], j[last]);
		}
	}

}
